package com.broada.apm.common.util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.cache.AreaManager;
import com.broada.apm.entity.IPLocation;
import com.broada.apm.utils.ApmFileUtils;
import com.broada.apm.utils.IPUtils;
import com.google.common.collect.Lists;

/**
 * 
 * @author xiangsy Create By 2015年3月26日 下午14:20:58 内置库cvs文件导入处理类 每行字段分别格式:
 *         area_code,ip_start, ip_end,memo
 */
public class CsvParserUtil {
	private static Logger LOG = LoggerFactory.getLogger(CsvParserUtil.class);
	private InputStreamReader fr = null;
	private BufferedReader br = null;

	public CsvParserUtil(String file) {
		try {
			File f = ApmFileUtils.getFile(file);
			FileInputStream fis = new FileInputStream(f);
			// 这里如果csv文件编码格式是GBK,改成GBK即可
			fr = new InputStreamReader(fis, "GBK");
		} catch (FileNotFoundException e) {
			LOG.error(e.getMessage());
			LOG.debug("csv上传文件未找到", e);
		} catch (UnsupportedEncodingException e) {
			LOG.error(e.getMessage());
			LOG.debug("csv文件编码错误!", e);
		}
	}

	/**
	 * 解析csv文件 到一个list中 每个单元个为一个String类型记录
	 * 
	 * @return
	 * @throws IOException
	 */
	public List<List<String>> readCSVFile() {
		br = new BufferedReader(fr);
		String strLine = null;// 一行
		List<List<String>> FileText = new ArrayList<List<String>>();
		try {
			while ((strLine = br.readLine()) != null) {
				String[] fields = strLine.split("\\s*,\\s*");
				// StringUtils会将两个","之间的空格数据截取去掉影响数据顺序,导致后面的按顺序取值出错
				// String[] fields = StringUtils.split(strLine, "\\s*,\\s*");
				FileText.add(Lists.newArrayList(fields));
			}
		} catch (Exception e) {
			LOG.error(e.getMessage());
			LOG.debug("csv文件读取异常!", e);
		} finally {
			try {
				if (fr != null) {
					fr.close();
				}
			} catch (IOException e) {
				LOG.error(e.getMessage());
				LOG.debug("csv文件输入流关闭异常!", e);
			}
			try {
				if (br != null) {
					br.close();
				}
			} catch (IOException e) {
				LOG.error(e.getMessage());
				LOG.debug("csv文件流关闭异常!", e);
			}
		}
		return FileText;
	}

	/**
	 * 将解析出来的CSV文件list转换成IPLocation的java对象数组
	 * 
	 * @return
	 * @throws Exception
	 * @throws IOException
	 */
	public List<IPLocation> listToIpObj(List<List<String>> FileText) throws Exception {
		List<IPLocation> listIP = new ArrayList<IPLocation>();

		// i==1,跳过文件头
		for (int i = 1; i < FileText.size(); i++) {
			List<String> textLine = FileText.get(i);
			// 至少有两个字段有值才是有效数据
			if (textLine.size() < 2) {
				continue;
			}
			IPLocation ipo = new IPLocation();
			String endIp = null;
			String memo = null;
			
			String areaCode = getUsefulAreaCode(textLine.get(0).trim()); // 拼接地区编号
			String startIp = textLine.get(1).trim();
			if (textLine.size() > 2) {
				endIp = textLine.get(2).trim();
			}
			if (StringUtils.isNotBlank(endIp) && StringUtils.isBlank(startIp)) {
				startIp = endIp;
				endIp = null;
			}
			if (textLine.size() > 3) {
				memo = textLine.get(3).trim();
			}
			// 只有当地区编码不为空,开始地址和结束地址至少一个有效的时候并且有效的IP地址为正确的,才是有效数据
			// 1,没有地区编码,无效数据; 2,开始IP和结束IP都为空,无效数据
			if (StringUtils.isBlank(areaCode) || (StringUtils.isBlank(startIp) && StringUtils.isBlank(endIp))
					|| AreaManager.getInstance().getAreaByCode(areaCode) == null) {
				continue;
			}
			// 开始IP和结束IP至少有一个不为空,不为空的不符合规范,无效数据
			// IP转长整型
			if (StringUtils.isNotBlank(startIp)) {
				if (isIP(startIp)) {
					ipo.setStartIpNum(IPUtils.toLittleEndianLong(startIp));
				} else {
					throw new Exception("ip格式不符合规则");
				}
			}
			if (StringUtils.isNotBlank(endIp)) {
				if (isIP(endIp)) {
					ipo.setEndIpNum(IPUtils.toLittleEndianLong(endIp));
				} else {
					throw new Exception("ip格式不符合规则");
				}
			}
			ipo.setAreaCode(areaCode);
			ipo.setStartIp(startIp);
			ipo.setEndIp(endIp);
			ipo.setMemo(memo);
			listIP.add(ipo);
		}
		return listIP;
	}
	
	private String getUsefulAreaCode(String areaCode) {
		if (areaCode.length() > 0 && areaCode.length() <= 2) { // 读到的是1位或2位的，补为4位，如果没有，再补为8位
			int length = 4 - areaCode.length();
			for (int j = 0; j < length; j++) {
				areaCode = "0" + areaCode;
			}
			if (AreaManager.getInstance().getAreaByCode(areaCode) == null) {
				for (int j = 0; j < 4; j++) {
					areaCode = "0" + areaCode;
				}
			}
		} else if (areaCode.length() > 2 && areaCode.length() <= 4) { // 读到的是3位或4位的，补为6位，如果没有，再补为8位
			int length = 6 - areaCode.length();
			for (int j = 0; j < length; j++) {
				areaCode = "0" + areaCode;
			}
			if (AreaManager.getInstance().getAreaByCode(areaCode) == null) {
				for (int j = 0; j < 2; j++) {
					areaCode = "0" + areaCode;
				}
			}
		} else if (areaCode.length() > 4 && areaCode.length() < 8) { // 读到的是5位或6位或7位的，补为8位
			int length = 8 - areaCode.length();
			for (int j = 0; j < length; j++) {
				areaCode = "0" + areaCode;
			}
		}
		return areaCode;
	}

	/**
	 * 判断是否为IP地址
	 * 
	 * @param addr
	 * @return
	 */
	public static boolean isIP(String ip) {

		if (ip.length() < 7 || ip.length() > 15 || "".equals(ip)) {
			return false;
		}
		// 判断IP格式和范围
		String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
		Pattern pat = Pattern.compile(rexp);
		Matcher mat = pat.matcher(ip);
		boolean isIp = mat.find();
		return isIp;
	}

}